canvas
element works like a
div
. width
and height
attributes. getContext
to get the context on which to draw.<div> <script type="text/javascript"> function draw(){ var canvas = document.getElementById('tutorial'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); } } </script> <canvas style="border: 1px solid black" id="tutorial" width="150" height="150"></canvas> </div>
function draw(){ var canvas = document.getElementById('tutorial'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); ctx.fillRect(25,25,100,100); ctx.clearRect(45,45,60,60); ctx.strokeRect(50,50,50,50); } }draw() [9]
function drawpath(){ var canvas = document.getElementById('tutorial2'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.moveTo(75,50); ctx.lineTo(100,75); ctx.lineTo(100,25); ctx.fill(); } }drawpath() [10]
function drawface(){ var canvas = document.getElementById('tutorial3'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle ctx.moveTo(110,75); ctx.arc(75,75,35,0,Math.PI,false); // Mouth (clockwise) ctx.moveTo(65,65); ctx.arc(60,65,5,0,Math.PI*2,true); // Left eye ctx.moveTo(95,65); ctx.arc(90,65,5,0,Math.PI*2,true); // Right eye ctx.stroke(); } }drawface() [11]
function drawcallout(){ var canvas = document.getElementById('tutorial4'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); // Quadratric curves example ctx.beginPath(); ctx.moveTo(75,25); ctx.quadraticCurveTo(25,25,25,62.5); ctx.quadraticCurveTo(25,100,50,100); ctx.quadraticCurveTo(50,120,30,125); ctx.quadraticCurveTo(60,120,65,100); ctx.quadraticCurveTo(125,100,125,62.5); ctx.quadraticCurveTo(125,25,75,25); ctx.stroke(); } }drawcallout() [12]
function drawheart(){ var canvas = document.getElementById('tutorial5'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); // Bezier curves example ctx.beginPath(); ctx.moveTo(75,40); ctx.bezierCurveTo(75,37,70,25,50,25); ctx.bezierCurveTo(20,25,20,62.5,20,62.5); ctx.bezierCurveTo(20,80,40,102,75,120); ctx.bezierCurveTo(110,102,130,80,130,62.5); ctx.bezierCurveTo(130,62.5,130,25,100,25); ctx.bezierCurveTo(85,25,75,37,75,40); ctx.fill(); } }drawheart() [13]
mozDrawText()
(fillText
in 3.1) writes text.function writetext(){ var canvas = document.getElementById('tutorial'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); ctx.translate(10,50); ctx.fillStyle = "red"; ctx.mozDrawText("Hello There"); ctx.stroke(); //in Firefox 3.1 this will be: //ctx.fillText("Hello There", 0,0); } }writetext() [15]
mozTextAlongPath
does just that.var manifesto = 'The Internet is becoming an increasingly important part of our lives. ' + 'The Mozilla project is a global community of people who believe that openness, innovation, and opportunity are key to the continued health of the Internet. We have worked together since 1998 to ensure that the Internet is developed in a way that benefits everyone. We are best known for creating the Mozilla Firefox web browser. ' + 'The Mozilla project uses a community-based approach to create world-class open source software and to develop new types of collaborative activities. We create communities of people involved in making the Internet experience better for all of us. ' + 'As a result of these efforts, we have distilled a set of principles that we believe are critical for the Internet to continue to benefit the public good as well as commercial aspects of life'; var numsegs = 5; var amplitude = 40; function draw() { canvas= document.getElementById('tutorial2'); var width = canvas.width; var height = canvas.height; var ctx = canvas.getContext('2d'); ctx.fillStyle = 'white'; ctx.fillRect(0, 0, width, height); ctx.save(); ctx.translate(10, height/2); var segwidth = width/numsegs; ctx.moveTo(0,0); for(var i = 0; i < numsegs; i++) { var dx = segwidth * i; var dy = i % 2 ? amplitude : -amplitude; var cpx = dx + segwidth*0.5; var cpy = dy; ctx.bezierCurveTo(cpx,cpy,cpx,cpy,dx+segwidth,0); } ctx.fillStyle = "black"; ctx.mozTextAlongPath(manifesto, false); ctx.restore(); }draw() [16]
Image
or use one from
document.images
. drawImage
to draw it on the canvas. function drawchart() { var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.src = 'backdrop.png'; img.onload = function(){ ctx.drawImage(img,0,0); ctx.beginPath(); ctx.moveTo(30,96); ctx.lineTo(70,66); ctx.lineTo(103,76); ctx.lineTo(170,15); ctx.stroke(); } }drawchart() [17]
drawImage(image, xpos, ypos, width,
height)
drawImage(image, sourcex, sourcey, sourcewidth, sourceheight, destx, desty, destwidth, destheight)
. // these all set the fillStyle to 'orange' ctx.fillStyle = "orange"; ctx.fillStyle = "#FFA500"; ctx.fillStyle = "rgb(255,165,0)"; ctx.fillStyle = "rgba(255,165,0,1)";
fillStyle
or strokeStyle
function drawcolors() { var ctx = document.getElementById('canvas').getContext('2d'); for (i=0;i<6;i++){ for (j=0;j<6;j++){ ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' + Math.floor(255-42.5*j) + ',0)'; ctx.fillRect(j*25,i*25,25,25); } } }drawcolors() [18]
function drawtransparency() { var ctx = document.getElementById('canvas2').getContext('2d'); // draw background ctx.fillStyle = '#FD0'; ctx.fillRect(0,0,75,75); ctx.fillStyle = '#6C0'; ctx.fillRect(75,0,75,75); ctx.fillStyle = '#09F'; ctx.fillRect(0,75,75,75); ctx.fillStyle = '#F30'; ctx.fillRect(75,75,150,150); ctx.fillStyle = '#FFF'; // set transparency value ctx.globalAlpha = 0.2; // Draw semi transparent circles for (i=0;i<7;i++){ ctx.beginPath(); ctx.arc(75,75,10+10*i,0,Math.PI*2,true); ctx.fill(); } }drawtransparency() [19]
function drawlineargradient() { var ctx = document.getElementById('canvas3').getContext('2d'); // Create gradients var lingrad = ctx.createLinearGradient(0,0,0,150); lingrad.addColorStop(0, '#00ABEB'); lingrad.addColorStop(0.5, '#fff'); lingrad.addColorStop(0.5, '#26C000'); lingrad.addColorStop(1, '#fff'); var lingrad2 = ctx.createLinearGradient(0,50,0,95); lingrad2.addColorStop(0.5, '#000'); lingrad2.addColorStop(1, 'rgba(0,0,0,0)'); // assign gradients to fill and stroke styles ctx.fillStyle = lingrad; ctx.strokeStyle = lingrad2; // draw shapes ctx.fillRect(10,10,130,130); ctx.strokeRect(50,50,50,50); }drawlineargradient() [20]
createRadialGradient
works similarly.lineWidth
is the width used. lineCap
is either "butt", "round", or "square". function drawlines() { var ctx = document.getElementById('canvas').getContext('2d'); var lineCap = ['butt','round','square']; // Draw guides ctx.strokeStyle = '#09f'; ctx.beginPath(); ctx.moveTo(10,10); ctx.lineTo(140,10); ctx.moveTo(10,140); ctx.lineTo(140,140); ctx.stroke(); // Draw lines ctx.strokeStyle = 'black'; for (i=0;i<lineCap.length;i++){ ctx.lineWidth = 15; ctx.lineCap = lineCap[i]; ctx.beginPath(); ctx.moveTo(25+i*50,10); ctx.lineTo(25+i*50,140); ctx.stroke(); } }drawlines() [21]
function drawlinejoin() { var ctx = document.getElementById('canvas2').getContext('2d'); var lineJoin = ['round','bevel','miter']; ctx.lineWidth = 10; for (i=0;i<lineJoin.length;i++){ ctx.lineJoin = lineJoin[i]; ctx.beginPath(); ctx.moveTo(-5,5+i*40); ctx.lineTo(35,45+i*40); ctx.lineTo(75,5+i*40); ctx.lineTo(115,45+i*40); ctx.lineTo(155,5+i*40); ctx.stroke(); } }drawlinejoin() [22]
save()
and restore()
push the current state (styles) of the canvas into a stack.var ctx = document.getElementById('canvas').getContext('2d'); ctx.fillRect(0,0,150,150); // draw a rectangle with default settings ctx.save(); // Save the default state ctx.fillStyle = '#09F' // Make changes to the settings ctx.fillRect(15,15,120,120); // Draw a rectangle with new settings ctx.save(); // Save the current state ctx.fillStyle = '#FFF' // Make changes to the settings ctx.globalAlpha = 0.5; ctx.fillRect(30,30,90,90); // Draw a rectangle with new settings
translate(x,y)
. Make sure you save
before. function drawtranslate() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.fillRect(0,0,300,300); for (var i=0;i<3;i++) { for (var j=0;j<3;j++) { ctx.save(); ctx.strokeStyle = "#9CFF00"; ctx.translate(50+j*100,50+i*100); drawSpirograph(ctx,20*(j+2)/(j+1),-8*(i+3)/(i+1),10); ctx.restore(); } } } function drawSpirograph(ctx,R,r,O){ var x1 = R-O; var y1 = 0; var i = 1; ctx.beginPath(); ctx.moveTo(x1,y1); do { if (i>20000) break; var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72)) var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72)) ctx.lineTo(x2,y2); x1 = x2; y1 = y2; i++; } while (x2 != R-O && y2 != 0 ); ctx.stroke(); }drawtranslate() [27]
rotate(angle)
scale(x,y)
var compositeTypes = [ 'source-over','source-in','source-out','source-atop', 'destination-over','destination-in','destination-out','destination-atop', 'lighter','darker','copy','xor' ]; function drawcompositing(){ for (i=0;i<compositeTypes.length;i++){ var label = document.createTextNode(compositeTypes[i]); document.getElementById('lab'+i).appendChild(label); var ctx = document.getElementById('tut'+i).getContext('2d'); // draw rectangle ctx.fillStyle = "#09f"; ctx.fillRect(15,15,70,70); // set composite property ctx.globalCompositeOperation = compositeTypes[i]; // draw circle ctx.fillStyle = "#f30"; ctx.beginPath(); ctx.arc(75,75,35,0,Math.PI*2,true); ctx.fill(); } }
function drawclip() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.fillRect(0,0,150,150); ctx.translate(75,75); // Create a circular clipping path ctx.beginPath(); ctx.arc(0,0,60,0,Math.PI*2,true); ctx.clip(); // draw background var lingrad = ctx.createLinearGradient(0,-75,0,75); lingrad.addColorStop(0, '#232256'); lingrad.addColorStop(1, '#143778'); ctx.fillStyle = lingrad; ctx.fillRect(-75,-75,150,150); // draw stars for (j=1;j<50;j++){ ctx.save(); ctx.fillStyle = '#fff'; ctx.translate(75-Math.floor(Math.random()*150), 75-Math.floor(Math.random()*150)); drawStar(ctx,Math.floor(Math.random()*4)+2); ctx.restore(); } } function drawStar(ctx,r){ ctx.save(); ctx.beginPath() ctx.moveTo(r,0); for (i=0;i<9;i++){ ctx.rotate(Math.PI/5); if(i%2 == 0) { ctx.lineTo((r/0.525731)*0.200811,0); } else { ctx.lineTo(r,0); } } ctx.closePath(); ctx.fill(); ctx.restore(); }drawclip() [29]
setInterval(function, delay)
and setTimeout(function, delay)
. var sun = new Image(); var moon = new Image(); var earth = new Image(); function init(){ sun.src = 'sun.png'; moon.src = 'moon.png'; earth.src = 'earth.png'; setInterval('draw()',100); } function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.globalCompositeOperation = 'destination-over'; ctx.clearRect(0,0,300,300); // clear canvas ctx.save(); ctx.fillStyle = 'rgba(0,0,0,0.4)'; ctx.strokeStyle = 'rgba(0,153,255,0.4)'; ctx.translate(150,150); // Earth var time = new Date(); ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() ); ctx.translate(105,0); ctx.fillRect(0,-12,50,24); // Shadow ctx.drawImage(earth,-12,-12); // Moon ctx.save(); ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() ); ctx.translate(0,28.5); ctx.drawImage(moon,-3.5,-3.5); ctx.restore(); ctx.restore(); ctx.beginPath(); ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit ctx.stroke(); ctx.drawImage(sun,0,0); }init();draw(); [30]
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="9cm" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <circle cx="6cm" cy="2cm" r="100" fill="red" transform="translate(0,50)" /> <circle cx="6cm" cy="2cm" r="100" fill="blue" transform="translate(70,150)" /> <circle cx="6cm" cy="2cm" r="100" fill="green" transform="translate(-70,150)" /> </g> </svg>
circles.xml
then use this html:
<object width="480" height="360" type="image/svg+xml" data="circles.xml"></object>
svg
element. width
and height
attributes. Top left is (0,0).viewBox
attribute tells user agent to
map full image onto view
canvas. preserveAspectRatio
controls the mapping.g
element is used for grouping <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <rect x="20" y="20" rx="0" ry="0" fill="red" width="20%" height="20%"/> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <circle cx="100" cy="100" r="90px" fill="blue" /> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <line x1="10" y1="10" x2="190" y2="190" stroke="blue" stroke-width="4" /> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <polyline points="10,190 20,190 20,150 50,150 50,190 80,190 80,110 110,110 110,190 140,190 140,70 170,70 170,190 190,190" stroke="blue" fill="darkblue" stroke-width="4" /> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <polygon points="100,10 40,180 190,60 10,60 160,180 100,10" stroke="blue" fill="darkblue" stroke-width="4" fill-rule="nonzero" /> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g stroke="black" stroke-width="0.1cm"> <image x="0" y="20" width="200" height="180" xlink:href="backdrop.png" /> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g stroke="black" stroke-width="1px"> <text x="50%" y="50%," dx="0,0,0,0,20" dy="0,0,0,0,8" rotate="20,30,40,50,0,0,-10" textLength="..." lengthAdjust="..." font-size="30" text-anchor="middle" >Hello World</text> </g> </svg>
stroke
and
fill
attributes. Class | Explanation | Example |
---|---|---|
Keyword |
SVG defines everything from 'aliceblue' to 'yellowgreen' on its type page [34]. | Aliceblue |
Functional |
A functional way to define the color. Either values in the range from 0 to 255 or percentages can be used. Mixing percents and values is illegal. | rgb(255,255,255) rgb(100%,100%,100%) |
Hexadecimal |
This is the same way colors are defined in HTML. | #FFFFFF |
URI |
A reference to a color gradient or pattern. Described later... | url(#MyGradient) |
opacity
,
fill-opacity
, stroke-opacity
, and
stop-opacity
(for gradients). There are
percentages.g
within a
defs
and then re-use it with a
use
. <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="250px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <defs> <g id="group1" fill="green" opacity="0.9" > <rect x="20" y="20" width="100" height="100" opacity="0.5" /> <rect x="80" y="80" width="100" height="100" fill="gray" /> </g> </defs> <use x="0" y="0" width="200" height="200" xlink:href="#group1" /> <use x="0" y="0" width="200" height="200" xlink:href="#group1" transform="rotate(70, 100, 100)" /> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" width="100%" height="200" viewBox="0 0 1200 200" > <defs> <linearGradient id="myFillGrad" > <stop offset="5%" stop-color="red" /> <stop offset="95%" stop-color="blue" stop-opacity="0.5" /> </linearGradient> </defs> <!-- Gradient Example --> <rect x="20" y="20" width="1160" height="160" fill="url(#myFillGrad)" stroke="black" stroke-width="2" /> </svg>
transform
attribute can be set to
translate(x,y)
scale(sx,sy)
rotate(angle,cx,cy)
skewX(angle)
skewY(angle)
matrix(a,b,c,d,e,f)
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" width="200" height="100" viewBox="-10 -5 110 55" > <defs> <g id="example"> <rect width="20" height="20" opacity="0.8" stroke="black" /> </g> </defs> <!-- Translate then rotate --> <use xlink:href="#example" fill="red" /> <g transform="translate(15, 15)" fill="yellow"> <use xlink:href="#example" /> <g transform="rotate(30)" fill="green"> <use xlink:href="#example" /> </g> </g> <!-- Rotate then translate --> <g transform="translate(70)"> <use xlink:href="#example" fill="red" /> <g transform="rotate(30)" fill="yellow"> <use xlink:href="#example" /> <g transform="translate(15, 15)" fill="green"> <use xlink:href="#example" /> </g> </g> </g> </svg>
path
to specify a path. <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm"> <path d="M100,10 L100,10 40,180 190,60 10,60 160,180 z" stroke="blue" fill="darkblue" stroke-width="4" /> </g> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <defs> <linearGradient id="hill" x1="100%" y1="100%" x2="100%" y2="0%"> <stop offset="5%" stop-color="green" /> <stop offset="95%" stop-color="lightgreen" stop-opacity="0.8" /> </linearGradient> </defs> <path d="M40,140 L40,100 10,100 C10,10 90,10 90,100 L60,100 60,140 M140,50 C70,180 195,180 190,100 " stroke="darkgreen" stroke-width="4" fill="url(#hill)" /> <circle cx="10" cy="10" r="4" fill="none" stroke="red" /> <circle cx="90" cy="10" r="4" fill="none" stroke="red" /> <line x1="10" y1="10" x2="10" y2="100" stroke="black" stroke-width="2" opacity="0.5" /> <line x1="90" y1="10" x2="90" y2="100" stroke="black" stroke-width="2" opacity="0.5" /> <circle cx="70" cy="180" r="4" fill="none" stroke="red" /> <circle cx="195" cy="180" r="4" fill="none" stroke="red" /> <line x1="70" y1="180" x2="140" y2="50" stroke="black" stroke-width="2" opacity="0.5" /> <line x1="195" y1="180" x2="190" y2="100" stroke="black" stroke-width="2" opacity="0.5" /> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <defs> <path id="path1" d="M25, 100 C10,10 175,10 175,100" /> </defs> <use xlink:href="#path1" fill="none" stroke="red" /> <text font-size="19.5" fill="blue"> <textPath xlink:href="#path1">Hello text-on-a-path world!</textPath> </text> </svg>
$(document).ready(function() { $('#canvas').svg({onLoad: drawInitial});}); function drawInitial(svg) { svg.circle(75, 75, 50, {fill: 'none', stroke: 'red', 'stroke-width': 3}); var g = svg.group({stroke: 'black', 'stroke-width': 2}); svg.line(g, 15, 75, 135, 75); svg.line(g, 75, 15, 75, 135); }
$('#canvas').svg('get').rect(50,50,15,15,{fill: 'none', stroke: 'blue', 'stroke-width': 3});
This talk available at http://jmvidal.cse.sc.edu/talks/canvassvg/
Copyright © 2009 José M. Vidal
.
All rights reserved.
05 March 2009, 09:42AM